#include "DumpFuncAddress.h"
#include "TString.h"
#include "SvrBase.h"

const char* sbase::DumpFuncAddress(int nLevel, char* pBuf, int nBufLen, PEXCEPTION_POINTERS pException)
{	
	if(!pBuf)
		return "";

	pBuf[0]=0;
	IF_NOT(nBufLen)
	{
		ASSERT(false);
		return "";
	}

	try
	{
		typedef struct STACK
		{
			STACK *	Ebp;
			PBYTE	Ret_Addr;
			DWORD	Param[0];
		} STACK, * PSTACK;

		STACK	Stack = {0, 0};
		PSTACK	Ebp;
		int nPos=0;

		sbase::sstring str;
		if (pException)	//fake frame for exception address
		{
			Stack.Ebp = (PSTACK)pException->ContextRecord->Ebp;
			Stack.Ret_Addr = (PBYTE)pException->ExceptionRecord->ExceptionAddress;
			Ebp = &Stack;
		}
		else
		{
			Ebp = (PSTACK)&nLevel - 1;	//frame addr of DumpFuncAddress()
		}


		CHAR	Module_Name[1024]={0,};
		PBYTE	Module_Addr = 0;
		PBYTE	Module_Addr1;
		//	bool bData=false;
		// Break trace on wrong stack frame.
		for (int Ret_Addr_I = 0;Ret_Addr_I <= nLevel ;)
		{
			if(IsBadReadPtr(Ebp, sizeof(PSTACK)) || IsBadCodePtr(FARPROC(Ebp->Ret_Addr)))
				break;

			if(pBuf)
			{
				if (Get_ModuleByAddr(Ebp->Ret_Addr, Module_Name,sizeof(Module_Name), Module_Addr1))
				{				
					if(Module_Addr1 != Module_Addr)
					{
						Module_Addr = Module_Addr1;					
						str.format("(%s %p:%i) ", Module_Name, Ebp->Ret_Addr/*-Module_Addr*/,Ret_Addr_I);					
					}
					else
					{
						str.format("(%p:%i) ", Ebp->Ret_Addr-Module_Addr,Ret_Addr_I);
					}
				}
				else
				{
					Module_Addr = Module_Addr1;					
					str.format("(%s %p:%i) ", Module_Name, PBYTE(Ebp->Ret_Addr/*-Module_Addr*/),Ret_Addr_I);					
				}

				int nPrintLen = str.length();
				if (nPos + nPrintLen < nBufLen)
				{
					_snprintf(pBuf+nPos,nBufLen-1-nPos, "%s", str.c_str());
				}
				else
				{
					memcpy_s(pBuf+nPos,nBufLen - nPos-1, str.c_str(), nBufLen - nPos-1);
					pBuf[nBufLen-1] = 0;
					return pBuf;
				}

				nPos += nPrintLen;
			}

			if(Ret_Addr_I == nLevel)
				return pBuf;

			Ret_Addr_I++;
			Ebp = Ebp->Ebp;
		}
	}
	catch(...)
	{
	}

	return pBuf;
}

BOOL sbase::Get_ModuleByAddr(PBYTE Ret_Addr, PCHAR Module_Name,const DWORD dwBufSize, PBYTE & Module_Addr)
{
	Module_Name[0] = 0;
	if(!Ret_Addr)
	{
		return 0;
	}
	if(!dwBufSize)
	{
		return 0;
	}

	MEMORY_BASIC_INFORMATION mbi={0,};
	VirtualQuery((void*)Ret_Addr,&mbi,sizeof(mbi));
	if(!mbi.AllocationBase)
	{
		return false;
	}

	Module_Addr=(PBYTE)mbi.AllocationBase;
	char szModuleFilePath[1024]={0,};
	GetModuleFileNameA((HMODULE)mbi.AllocationBase,szModuleFilePath,sizeof(szModuleFilePath)-1);
	char* pchToken=strrchr(szModuleFilePath,'\\');
	if(pchToken)
	{
		++pchToken;
	}
	else
	{
		pchToken=szModuleFilePath;
	}
	strncpy(Module_Name,pchToken,dwBufSize-1);
	return true;
}

